package juego.modelo;

import java.util.ArrayList;
import java.util.Iterator;

public class Tablero {

	private static Tablero INSTANCE = null;
	private int nivel;
	private int distanciaEntreComidas;
	private Punto[][] caminos;
	private Comida[][] comidas;
	private Punto[][] paredes;
	private int puntajeActual;
	private int cantidadPuntosComunes;
	private int cantidadFantasmas;
	private ArrayList<Fantasma> fantasmas;
	private Pacman pacman;
	private Resultados resultados;
	private int tamanoMapa;
	boolean enJuego= false;
	Iterator<Fantasma> iterador;
	public Punto posicionInicialPacman;
	private Punto posicionInicialFantasmas;
	private ArrayList<Punto> puntosPoder;
	private MapaFactory mapa; 

	private Tablero() {
		this.puntajeActual=0;
		this.distanciaEntreComidas=20;
	}

	private synchronized static void createInstance() {
		if (INSTANCE == null) {
			INSTANCE = new Tablero();
		}
	}

	public static Tablero getInstance() {
		if (INSTANCE == null)
			createInstance();
		return INSTANCE;
	}
	
	public void crearJuego(int nivel){
		if( nivel < 0 ) throw new IllegalArgumentException();
		Tablero tablero = Tablero.getInstance();
		tablero.setNivel(nivel);
		this.mapa = null;
		this.mapa = new MapaFactory(nivel);
		tablero.crearPacman(mapa);
		tablero.crearFantasmas(mapa);
		this.resultados= new Resultados();;
		enJuego = true;
	}
	
    private void setNivel(int nivel) {
		this.nivel=nivel;
	}

	private void crearFantasmas(MapaFactory mapa){
		fantasmas = new ArrayList<Fantasma>(this.getCantidadFantasmas());
		int cantidadDeEstrategias = 4;
		Punto posFantasma = this.posicionInicialFantasmas;
		for (int i = this.getCantidadFantasmas(); i > 0; i--) {
			int tipo = i % cantidadDeEstrategias;                                           
			switch(tipo){
			/* Crea los fantasmas */
			case(0): fantasmas.add(new Fantasma ("Shadow",new EstrategiaOfensiva(), pacman, posFantasma, nivel)); break;
			case(1): fantasmas.add(new Fantasma ("Speedy",new EstrategiaAleatorea(), pacman, posFantasma, nivel)); break;
			case(2): fantasmas.add(new Fantasma ("Pokey", new EstrategiaTerritorial(), pacman, posFantasma, nivel)); break;
			case(3): fantasmas.add(new Fantasma ("Bashful", new EstrategiaDefensiva(), pacman, posFantasma, nivel)); break;
			}
		};
		 iterador = fantasmas.iterator();
	}
		 
    private void crearPacman(MapaFactory mapa) {
    	this.pacman = new Pacman(this.posicionInicialPacman);
		pacman.setEstadoPoderoso(false);
	}
    
    public void sumarPuntos(int puntaje){
    	this.puntajeActual+=puntaje;
	}
    
   public Punto getProximoPunto(Punto puntoActual, Movimiento movimiento) {
	  	int x = puntoActual.getPuntoX()/distanciaEntreComidas ;
		int y = puntoActual.getPuntoY()/distanciaEntreComidas ;
		switch (movimiento) {
		case DERECHA:
			if (puntoActual.getPuntoY() % distanciaEntreComidas == 0) {
				if (caminos[x + 1][y] != null)
					return new Punto(puntoActual.getPuntoX() + 1, puntoActual
							.getPuntoY());
			}
			break;
		case IZQUIERDA:
			if (puntoActual.getPuntoY() % distanciaEntreComidas == 0) {
				if ((puntoActual.getPuntoX() % distanciaEntreComidas == 0)
						&& (caminos[x - 1][y] == null))
					return puntoActual;
				if (caminos[x][y] != null)
					return new Punto(puntoActual.getPuntoX() - 1, puntoActual
							.getPuntoY());
			}
			break;
		case ARRIBA:
			if (puntoActual.getPuntoX() % distanciaEntreComidas == 0) {
				if ((puntoActual.getPuntoY() % distanciaEntreComidas == 0)
						&& (caminos[x][y - 1] == null))
					return puntoActual;
				if (caminos[x][y] != null)
					return new Punto(puntoActual.getPuntoX(), (puntoActual
							.getPuntoY() - 1));
			}
			break;
		case ABAJO:
			if (puntoActual.getPuntoX() % distanciaEntreComidas == 0) {
				if ((caminos[x][y + 1] != null)
						&& (puntoActual.getPuntoX() % distanciaEntreComidas) == 0)
					return new Punto(puntoActual.getPuntoX(), puntoActual
							.getPuntoY() + 1);
			}
			break;
		}
		return puntoActual;
	}
    
    public void cerrarJuego(){
    	enJuego = false;
	}
    
    public void desaparecerPersonajes() {
    	Iterator <Fantasma> iterador = fantasmas.iterator();
    	while (iterador.hasNext()) { 
    		Fantasma fantasma = iterador.next();   
			fantasma.desaparecer();
			};
		pacman.desaparecer();
	}
    
    public Comida getObjetoEnPosicion(Punto punto){
    	int x = punto.getPuntoX()/this.distanciaEntreComidas;
		int y = punto.getPuntoY()/this.distanciaEntreComidas;
		if((x<0)|(x>this.tamanoMapa))
			throw new IndexOutOfBoundsException ();
		if((y<0)|(y>this.tamanoMapa))
			throw new IndexOutOfBoundsException ();
		if((punto.getPuntoX()%this.distanciaEntreComidas==0)&&(punto.getPuntoX()%this.distanciaEntreComidas)==0)
		return getComidas()[x][y] ;
		else return null;
	}
    public void borrarComida(Punto posicion)
    {
    	int x = posicion.getPuntoX();
		int y = posicion.getPuntoY();
    	if(this.getComidas()[x][y]==null)
    		throw new IndexOutOfBoundsException();
    	this.getComidas()[x][y].setEstadoComido(true);
    	this.getComidas()[x][y]=null;
    	setCantidadPuntosComunes(getCantidadPuntosComunes() - 1);
    };
    
    public boolean estadoDelJuego(){
    	if(this.cantidadPuntosComunes==0)return false;
		return enJuego;
    }

	public void borrarPuntoPoder(Punto posicion) {
		borrarComida(posicion);
		Poder poder = new Poder(this.nivel, this.pacman);
		Thread t= new Thread(poder);
		t.start();
	}

	public Punto[][] getParedes() {
		return paredes;
	}

	public void setTamanoMapa(int tamanoMapa) {
		this.tamanoMapa = tamanoMapa;
	}

	public int getTamanoMapa() {
		return tamanoMapa;
	}

	public void setCaminos(Punto[][] caminos) {
		this.caminos = caminos;
	}

	public void setComidas(Comida[][] comidas) {
		this.comidas = comidas;
	}

	public Comida[][] getComidas() {
		return comidas;
	}

	public void setCantidadPuntosComunes(int cantidadPuntosComunes) {
		this.cantidadPuntosComunes = cantidadPuntosComunes;
	}

	public int getCantidadPuntosComunes() {
		return cantidadPuntosComunes;
	}

	public void setCantidadFantasmas(int cantidadFantasmas) {
		this.cantidadFantasmas = cantidadFantasmas;
	}

	public int getCantidadFantasmas() {
		return cantidadFantasmas;
	}
	public void setPosicionInicialPacman(Punto punto) {
		this.posicionInicialPacman = new Punto(punto.getPuntoX()
				* this.distanciaEntreComidas, punto.getPuntoY()
				* this.distanciaEntreComidas);
	}

	public void setPosicionInicialFantasma(Punto punto) {
		this.posicionInicialFantasmas = new Punto(punto.getPuntoX()
				* this.distanciaEntreComidas, punto.getPuntoY()
				* this.distanciaEntreComidas);
		;
	}

	public void setParedes(Punto[][] paredes) {
		this.paredes = paredes;
		
	}

	public int getDistanciaEntreComida() {
		return this.distanciaEntreComidas;
	}

	public Punto[][] getCaminos() {
		return this.caminos;
	}

	public Punto getPosicionInicialPacman() {
		return this.posicionInicialPacman;
	}

	public Punto getPosicionInicialFantasmas() {
		return this.posicionInicialFantasmas;
	}

	public void setPuntosPoder(ArrayList<Punto> posPuntoPoder) {
		this.puntosPoder=posPuntoPoder;
		
	}
	public ArrayList<Punto> getPuntosPoder(){
		return this.puntosPoder;
	}

	public MapaFactory getMapa() {
		return this.mapa;
	}

	public Pacman getPacman() {
		return this.pacman;
	}

	public ArrayList<Fantasma> getFantasmas() {
		return this.fantasmas;
	}

	public Bonus getBonus() {
		return this.mapa.getBonus();
	}

	public double getAngulo() {
			return this.pacman.getAngulo();
	}

	public Punto getPosicionPacman() {
		return this.pacman.getPosicion();
	}
	
	public int getPuntaje(){
		return this.puntajeActual;
	}

	public Resultados getResultados() {
		return this.resultados;
	}

	public void setPuntaje(int i) {
		this.puntajeActual=i;
	}
}
